using System; using System.Collections.Generic; using System.Text; namespace Woolworths.Barcode { /// <summary> /// Class deals with databar style barcodes where data is encoded into the barcode /// </summary> public class DataBar { // this is the string representing the FNC1 character or characters transmitted by the scanner // The FNC1 is encoded in two separate ways within GS1 DataMatrix: // • Start character // • Field Separator (to separate variable length article identifiers) private const string FNC1 = " \ u001D" ; /// <summary> /// used internally to hold the details of the databar pieces /// </summary> private struct internalBarPiece { public string raw; public string ID; public string Value; public int DataLength; public string DataType; public bool hasCheckdigit; public int decimals; } #region Old EAN number processing bits /// <summary> /// gets a product ID from a barcode /// </summary> /// <param name="Barc de"> barcode value as a string </param> /// <returns> a string value containing the item ID </returns> /// <remarks> blanks out issue numbers on EAN13 periodical items (barcodes starting with 977) </remarks> private stat ic string GetEAN13IDFromBarcode( string Barcde) { if (Barcde.Length == 13) { // take care of magazine item numbers (start with 977 and are 13 long) if (Barcde.StartsWith( "977" )) { // blank out the issue number and re - calculate the check digit. string sTmp = Barcde.Substring(0, 10) + "00" ; sTmp += Barcode.CheckDigit.EAN13(sTmp); return sTmp; } else { string sTmpItmID = string .Empty; // Random Mass Barcodes with price (13 long) Type 1 & Type 2 // Difference between Type 1 & 2 is the length of the // Unique Item Identifier, and thus the price filed as well switch (Barcde.Substring(0, 2)) { case "20" : sTmpItmID = Barcde.Substring(0, 6); break ; // type 1 case "28" : sTmpItmID = Barcde.Substring(0, 6); break ; // type 1 case "25" : sTmpItmID = Barcde.Substring(0, 6); break ; // type 1 case "29" : sTmpItmID = Barcde.Substring(0, 7); break ; // type 2 } if (sT mpItmID.Length > 0) return sTmpItmID.PadRight(12, '0' ) + Barcode.CheckDigit.EAN13(sTmpItmID.PadRight(12, '0' )); } } return Barcde.TrimStart( '0' ); } /// <summary> /// gets the Extended Price from a barcode (if applicable) /// </summary> /// <param name="Barcode"> intelligent Barcode to parse </param> /// <returns> 0 if not an 'intelligent' barcode, or price in cents </returns> private static int GetEAN13ExtendedPriceFromBarcode( string Barcode) { if (Barcode.Length != 13) return 0; switch (Barcode.Subst ring(0, 2)) { case "20" : case "25" : case "28" : return int .Parse(Barcode.Substring(7, 5)); // Type 1 (See Above) case "29" : return int .Parse(Barcode.Substring(8, 4)); // Type 2 (See Above) } return 0; } #endregion #region Convert UPC - E to UPC - A /// <summary> /// This will convert a UPC - E barcode to a UPC - A barcode /// </summary> /// <param name="UPCE"></param> /// <returns></returns> public static string UPCE2UPCA( string UPC E) { // Convert UPC - E to UPC - A format string ValidDigits; string Mfg; string Prod; string LastDigit; string UPCA; // Convert the UPC - E to UPC - A ValidDigits = UPCE.Substring(0, 6); LastDigit = UPCE.Substring(5, 1); if (LastDigit == "0" ) { Mfg = ValidDigits.Substring(0, 2) + ValidDigits.Substring(5, 1) + "00" ; Prod = "0 0" + ValidDigits.Substring(2, 3); } else if (LastDigit == "1" ) { Mfg = ValidDigits.Substring(0, 2) + ValidDigits.Substring(5, 1) + "00" ; Prod = "00" + ValidDigits.Substring(2, 3); } else if (LastDigit == "2" ) { Mfg = ValidDigits.Substring(0, 2) + ValidDigits.Substring(5, 1) + "00" ; Prod = "00" + ValidDigits.Substring(2, 3); } else if (LastDigit == "3" ) { Mfg = ValidDigits.Substring(0, 3) + "00" ; Prod = "000" + ValidDigits.Substring(3, 2); } else if (LastDigit == "4" ) { Mfg = ValidDigits.Sub string(0, 4) + "0" ; Prod = "0000" + ValidDigits.Substring(4, 1); } else { Mfg = ValidDigits.Substring(0, 5); Prod = "0000" + ValidDigits.Substring(5, 1); } // Return the 12 digit UPC - A code //UPCA = UPCE.Substring(1, 1) + Mfg + Prod + UPCE.Substring(6, 1); UPCA = Mfg + Prod + UPCE.Substring(6, 1); //} r eturn UPCA; } #endregion /// <summary> /// Decodes a barcode into it's constituent parts as per the data bar specification /// </summary> /// <remarks> for definition see http://www.gs1.org/sites/default/files/docs/barcodes/GS1_DataMatrix_Introduction_and_t echnical_overview.pdf</remarks > /// <param name="p_Barcode"> the barcode to decode </param> /// <param name="PossibleFNC1Indicators"> an array of possible FNC1 indicator tokens as per the GS1 DataBar specification </param> /// <returns> a dictionary of parts of data encoded into the barcode /// /// it's assumed that the characters /// • " \ uFFFD" - replacement character /// • " \ uFFFC" - object replacement character /// are also FNC1 characters /// /// </returns> public static Dictionary < string , string > DecodeBarcode( string p_Barcode, string [] PossibleFNC1Indicators) { string tmp = p_Barcode; foreach ( string F in PossibleFNC1Indicators) tmp = tmp.Replace(F, FNC1); return DecodeBarcode(p_Barcode); } /// <summary> /// Decodes a barcode into it's constituent parts as per the data bar specification /// </summary> /// <param name="p_Barcode"> the barcode to decode </param> /// <returns> a dictionary of parts of data encoded into the barcode </returns> /// <remarks> /// for definition see http:/ /www.gs1.org/sites/default/files/docs/barcodes/GS1_DataMatrix_Introduction_and_t echnical_overview.pdf /// /// testing strings : /// FNC101034531200000111709112510ABCD1234FNC1410 9501101020917 /// FNC101034531200000111708050810ABCD1234FNC14109501101020917 /// 8110106141416543213500110000210123196000 /// 01900123456789083103001750 /// 0198898765432106320201234515991231 /// 8101054321120021123456 /// 0190012345678908310301223315081231 /// /// -- invalid 8019 /// 01942112345001228019123456FNC115051210 /// </remarks> public static Dictionary < string , string > DecodeBarcode( string p_Barcode) { List <internalBarPiece> parts = new List <internalBarPiece>(); string barcodeRemaining = p_Barcode; s tring UPCA; internalBarPiece p; // standard characters that could be use in place of the standard FNC1 characters barcodeRemaining = barcodeRemaining.Replace( " \ uFFFD" , FNC1); // replacement ch aracter barcodeRemaining = barcodeRemaining.Replace( " \ uFFFC" , FNC1); // object replacement character // If a UPC - E barcode is scanned convert it to UPC - A if (p_Barcode.Length == 7) { UPCA = UPCE2UPCA(p_Barcode); p_Barcode = UPCA; } else if (p_Barcode.Length == 8 && (p_Barcode.StartsWith( "0" ) || p_Barcode.StartsWith( "1" ))) { UPCA = UPCE2UPCA(p_Barcode.Substring(1, 7)); p_Barcode = UPCA; } // convert old EAN13 price embedded barcodes into the databar format // assume it's an item number if (p_Barcode.Length <= 13) { // add the Item ID part p = new internalBarPiece(); p.ID = "01" ; // item ID p.Value = p_Barcode.PadLeft(14, '0' ); p.raw = "01" + p.Value; p.DataLength = 14; p.DataType = "Numeric" ; p.decimals = - 1; p.hasCheckdigit = false ; parts.Add(p); } else // is's probably databar, attempt to do what you do... { // reset the data type so we can s tart the loop p = new internalBarPiece(); p.DataType = "" ; while (barcodeRemaining.Length > 1 && p.DataType != "Undefined" ) { // if the piece starts with an FNC1, remove it so we're at the start of the data if (barcodeRemaining.StartsWith(FNC1)) barcodeRemaining = barcodeRemaining.Substring(FNC 1.Length); // get the part details and add to the list p = ParseNextPart(barcodeRemaining); // add the part ot the list parts.Add(p); // remove the previous part from string. barcodeRemaining = barcodeRemaining.Substring(p.raw.Length); } } // build the result Dictionary < string , string > result = new Dictionary < string , string >(); result.Add( "Input" , p_Barcode); for ( int i = 0; i < parts.Count; i++) { result.Add(parts[i].ID, parts[i].Value); if (parts[i].ID == "01" ) // item ID { // deal with old style price embeded barcodes by grabbing the price and converting to an item ID decimal price = decimal .Parse(GetEAN13ExtendedPriceFromBarcode(parts[i].Value.TrimStart( '0' )).ToString ()); if (price != 0) { // it's got a price embedded so the value is out... get the value without price embedded result[ "01" ] = GetEAN13ID FromBarcode(parts[i].Value.TrimStart( '0' )).PadLeft(14, '0' ); if (!result.ContainsKey( "390" )) result.Add( "390" , string .Format( "{0:#0.00}" , price / 100)); } } } return result; } private static internalBarPiece ParseNextPart( string Value) { internalBarPiece p = new internalBarPiece(); // setup defaults p.raw = string .Empty; p.hasCheckdigit = false ; p.ID = Value.Substring(0, 2); p.DataLength = - 1; p.DataType = "Undefined" ; p.decimals = - 1; // go through the permitations switch (p.ID) { cas e "00" : // Serial Shipping Container Code (SSCC - 18), Numeric(2 + 18), has checksum p.DataType = "Numeric" ; p.DataLength = 18; p.hasCheckdigit = true ; break ; case "01" : // Item ID / UPC/EAN, Numeric(2 + 14), has checksum p.DataType = "Numeric" ; p.DataLength = 14; p.hasCheckdigit = true ; break ; case "02" : // Number of containers, Numeric(2 + 14), has checksum p.DataType = "Numeric" ; p.DataLength = 14; p.hasCheckdigit = true ; break ; case "10" : // Batch Number, Alphanumeric(2 + 1 to 20) p.DataType = "Alphanumeric" ; p.raw = GetVariableLengthField(Value, p.ID.Length, 1, 20, 0); break ; case "11" : // Production Date, Date(2 + 6) YYMMDD case "12" : // Due date, Date(2 + 6) case "13" : // Packaging Date, Date(2 + 6) case "15" : // Sell by Date (Quality Control), Date(2 + 6) case "17" : // Exp iration Date, Date(2 + 6) p.DataType = "Date" ; p.DataLength = 6; break ; case "20" : // Product Variant, Numeric(2 + 2) p.DataType = "Numeric" ; p.DataLength = 2; break ; case "21" : // Serial Number, Alphanumeric(2 + 1 to 20) p.DataType = "Alphanumeric" ; p.raw = GetVariableLengthField(Value, p.ID.Length, 1, 20, 0); break ; case "24" : // multiple p.ID = Value.Substring(0, 3); switch (p.ID) { case "240" : // Additional Product Identification, Alphanumeric(3 + 1 to 30) p.DataType = "Alphanumeric" ; p.raw = GetVariableLengthField(Value, p.ID.Length, 1, 20, 0); break ; case "241" : // Customer part number, Alphanumeric(3 + 1 to 30) p.DataType = "Alphanumeric" ; p.raw = GetVariableLengthField(Value , p.ID.Length, 1, 30, 0); break ; default : // don't know what it is so assume a variable length field p.raw = GetVariab leLengthField(Value, p.ID.Length, 1, 65535, 0); break ; } break ; case "25" : // p.ID = Value.Substring(0, 3); switch (p.ID) { case "250" : // Second Serial Number, Alphanumeric(3 + 1 to 30) case "251" : // Reference to source entity, Alphanumeric(3 + 1 to 30) case "253" : // Global Document Type Identifier, Numeric(3 + 14 to 30) p.DataType = "Alphanumeric" ; p.raw = GetVariableLengthField(Value, p.ID.Length, 1, 30, 0); break ; case "254" : // GLN Extension Component, Alphanumeric(3 + 1 to 20) p.DataType = "Alphanumeric" ; p.raw = GetVariableLengthField(Value, p.ID.Length, 1, 20, 0); break ; default : // don't know what it is so assume a variable length field p.raw = GetVariabl eLengthField(Value, p.ID.Length, 1, 65535, 0); break ; } break ; case "30" : // Quantity Each, Numeric(2 + 1 to 8) p.DataType = "Numeric" ; p.raw = GetVariableLengthField(Value, p.ID.Length, 1, 8, 0); break ; case "31" : // multiple (y = number of decimals) all decimals Numeric(4 + 6) // 310y Product Net Weight in kg, Numeric(4 + 6) // 311y Product Length/1st Dimension, in meters, Numeric(4 + 6) // 312y Product Widt h/Diameter/2nd Dimension, in meters, Numeric(4 + 6) // 313y Product Depth/Thickness/3rd Dimension, in meters, Numeric(4 + 6) // 314y Product Area, in square meters, Numeric(4 + 6) // 315y Product Volume, in liters, Numeric(4 + 6) // 316y product Volume, in cubic meters, Numeric(4 + 6) case "32" : // multiple (y = number of decimals) // 320y Product Net Weight, in pounds, Numeric(4 + 6) // 321y Product Length/1st Dimension, in inches, Numeric(4 + 6) // 322y Product Length/1st Dimension, in feet, Numeric(4 + 6) // 323y Product Length/1st Dimension, in yards, Numeric(4 + 6) // 324y Product Width/Diameter/2nd Dimension, in inches, Numeric(4 + 6) // 325y Product Width/Diameter/2nd Dimension, in feet, N umeric(4 + 6) // 326y Product Width/Diameter/2nd Dimension, in yards, Numeric(4 + 6) // 327y Product Depth/Thickness/3rd Dimension, in inches, Numeric(4 + 6) // 328y Product Depth/Thickness/3rd Dimension, in feet, Numeric(4 + 6) // 329y Product Depth/Thickness/3rd Dimension, in yards, Numeric(4 + 6) case "33" : // multiple (y = numb er of decimals) // 330y Container Gross Weight (Kg), Numeric(4 + 6) // 331y Container Length/1st Dimension (Meters), Numeric(4 + 6) // 332y Container Width/Diameter/2nd Dimen sion (Meters), Numeric(4 + 6) // 333y Container Depth/Thickness/3rd Dimension (Meters), Numeric(4 + 6) // 334y Container Area (Square Meters), Numeric(4 + 6) // 335y Container Gross Volume (Liters), Numeric(4 + 6) // 336y Container Gross Volume (Cubic Meters), Numeric(4 + 6) // 337y Kilograms per square meter, Numeric(4 + 6) case "34" : // multiple (y = number of decimals) //340y Container Gross Weight (Pounds), Numeric(4 + 6) //341y Container Length/1st Dimension, in inches, Numeric(4 + 6) //342y Container Length/1st Di mension, in feet, Numeric(4 + 6) //343y Container Length/1st Dimension in, in yards, Numeric(4 + 6) //344y Container Width/Diameter/2nd Dimension, in inches, Numeric(4 + 6) //345y Container Width/Diameter/2nd Dimension, in feet, Numeric(4 + 6) //346y Container Width/Diameter/2nd Dimension, in yards, Numeric(4 + 6) //347y Container Depth/Thickness /Height/3rd Dimension, in inches, Numeric(4 + 6) //348y Container Depth/Thickness/Height/3rd Dimension, in feet, Numeric(4 + 6) //349y Container Depth/Thickness/Height/3rd Dimension, in yards, Numeric(4 + 6) case "35" : // multiple (y = number of decimals) //350y Product Area (Square Inches), Numeric(4 + 6) //351y Product Area (Square Feet), Numeric(4 + 6) //352y Product Area (Square Yards), Numeric(4 + 6) //353y Container Area (Square Inches), Numeric(4 + 6) //354y Container Area (Square Feet), Numeric(4 + 6) //355y Con tainer Area (Square Yards), Numeric(4 + 6) //356y Net Weight (Troy Ounces), Numeric(4 + 6) //357y Kilograms per square meter, Numeric(4 + 6) case "36" : // Volume - multiple (y = number of decimals) //360y Product Volume (Quarts), Numeric(4 + 6) //361y Product Volume (Gallons), Numeric(4 + 6) //362y Container Gross Vo lume (Quarts), Numeric(4 + 6) //363y Container Gross Volume (Gallons), Numeric(4 + 6) //364y Product Volume (Cubic Inches), Numeric(4 + 6) //365y Product Volume (Cubic Feet), Numeric(4 + 6) //366y Product Volume (Cubic Yards), Numeric(4 + 6) //367y Container Gross Volume (Cubic Inches), Numeric(4 + 6) //36 8y Container Gross Volume (Cubic Feet), Numeric(4 + 6) //369y Container Gross Volume (Cubic Yards), Numeric(4 + 6) p.ID = Value.Substring(0, 3); p.DataType = "Numeric" ; p.DataLength = 6; p.decimals = int .Parse(Value.Substring(3, 1)); break ; case "37" : // Number of Units Contained, Numeric(2 + 1 to 8) p.DataType = "Numeric" ; p.raw = GetVariableLengthField(Value, p.ID.Length, 1, 8, 0); brea k ; case "39" : // Amount payable - multiple (y = number of decimals) p.ID = Value.Substring(0, 3); p.DataType = "Numeric" ; p.de cimals = int .Parse(Value.Substring(3, 1)); switch (p.ID) { case "390" : // 390y Amount payable - single monetary area, Numeric(4 + 1 to 15) p.raw = GetVariableLengthField(Value, p.ID.Length, 1, 15, 1); break ; case "391" : // 391y Amount payable with ISO currency code , Numeric(4 + 4 to 18) p.raw = GetVariableLengthField(Value, p.ID.Length, 4, 18, 1); break ; case "392" : // 392y Amount payable for a Variable Measure Trade Item single monetary unit, Numeric(4 + 1 to 15) p.raw = GetVariableLengthField(Value, p.ID.Length, 1, 15, 1); break ; case "393" : // 393y Amount payable for a Variable Measure Trade Item - with ISO currency code, Numeric(4 + 4 to 18) p.raw = GetVariableLengthField(Value, p.ID.Length, 4, 18, 1); break ; default : // don't know what it is so assume a variable length field p.raw = GetVariableLengthField(Value, p.ID.Length, 1, 65535, 0); break ; } break ; case "40" : // delive ry info p.ID = Value.Substring(0, 3); switch (p.ID) { case "400" : // 400 Customer Purchase Order Number, Alphanum eric(3 + 1 to 30) case "401" : // 401 Consignment number, Alphanumeric(3 + 1 to 30) p.DataType = "Alphanumeric" ; p.raw = GetVariableLengthField(Value, p.ID.Length, 1, 30, 0); break ; case "402" : // 402 Shipment Identification Number, Numeric(3 + 17) p.DataType = "Numeric" ; p.DataLength = 17; break ; case "403" : // 403 Routing code, Alphanumeric(3 + 1 to 30) p.DataType = "Alphanumeric" ; p.raw = GetVariableLengthField(Value, p.ID.Length, 1, 30, 0); break ; default : // don't know what it is so assume a variable length field p.raw = GetVariableLengthField(Value, p.ID. Length, 1, 65535, 0); break ; } break ; case "41" : // //410 Ship To/Deliver To Location Code (EAN13 or DUNS code), Numeric(3 + 13) Has checkdigit //411 Bill To/Invoice Location Code (EAN13 or DUNS code), Numeric(3 + 13) Has checkdigit //412 Purchase From Location Code (EAN13 or DUNS code), Numeric(3 + 13) Has checkdigit //413 Ship for - deliver for - forward to EAN.UCC Global Location Number, Numeric(3 + 13) Has checkdigit //414 Identification of a physical location EAN.UCC Global Location Number, Numeric(3 + 13) Has checkdigit //415 EAN.UCC Global Location Number of the invoicing party, Numeric(3 + 13) H as checkdigit p.DataType = "Numeric" ; p.ID = Value.Substring(0, 3); p.DataLength = 13; p.hasCheckdigit = true ; break ; case "42" : // p.ID = Value.Substring(0, 3); switch (p.ID) { case "420" : // 420 Ship To/Deliver To Postal Code (Single Postal Authority), Alphanumeric(3 + 1 to 20) p.DataType = "Alphanumeric" ; p.raw = GetVariable LengthField(Value, p.ID.Length, 1, 20, 0); break ; case "421" : // 421 Ship To/Deliver To Postal Code (Multiple Postal Authority), Alphanumeric(3 + 4 to 12) p.DataType = "Alphanumeric" ; p.raw = GetVariableLengthField(Value, p.ID.Length, 4, 12, 0); break ; case "422" : // 422 Country of origin of a trade item, Numeric(3 + 3) p.DataType = "Numeric" ; p.DataLength = 3; break ; case "423" : // 423 Country of Initial Processing, Numeric(3 + 3 to 15) p.DataType = "Numeric" ; p.raw = GetVariableLengthField(Value, p.ID.Length, 3, 15, 0); break ; case "424" : // 424 Country of Processing, Numeric(3 + 3) case "425" : //425 Country of Disassembly, Numeric(3 + 3) case "426" : //426 Country Covering full Process Chain, Numeric(3 + 3) p.DataType = "Numeric" ; p.DataLength = 3; break ; default : // don't know what it is so assume a variable length field p.raw = GetVariableLengthField(Value, p.ID.Length, 1, 65535, 0); break ; } break ; case "70" : // p.ID = Value.Substring(0, 4); switch (p.ID) { case "7001" : // 7001 NATO Stock Number (NSN), Numeric(4 + 13) p.DataType = "Numeric" ; p.DataLength = 13; break ; case "7002" : // 7002 UN/ECE Meat Carcasses and Cuts Classification, Alphanumeric(4 + 1 to 30) p.DataType = "Alphanumeric" ; p.raw = GetVariableLengthField(Value, p.ID.Length, 1, 30, 0); break ; case "7003" : // 7003 Expiration Date and Time, Numeric(4 + 10 to ) p.DataType = "Numeric" ; p.raw = GetVariableLengthField(Value, p.ID.Length, 6, 30, 0); break ; case "7004" : //7004 Active Potency, Numeric(4 + 1 to 4) p.DataType = "Numeric" ; p.raw = GetVariableLengthField(Value, p.ID.Length, 1, 4, 0); break ; //703s Approval Number of Processor with ISO Country Code (s = sequence #), Alphanumeric(4 + 3 to 31) case "7030" : case "7031" : case "7032" : case "7033" : case "7034" : case "7035" : case "7036" : case "7037" : case "7038" : case "7039" : p.DataType = "Alphanumeric" ; p.raw = GetVariableLengthField(Value, p.ID.Length, 3, 31, 0); break ; default : // don't know what it is so assume a variable length field p.raw = GetVariableLengthField(Value, p.ID.Length, 1, 65535, 0); break ; } break ; case "80" : // p.ID = Value.Substring(0, 4); switch (p.ID) { case "8001" : // 8001 Roll Products - Width/Length/Core Diameter, Numeric(4 + 14) p.DataType = "Numeric" ; p.DataLength = 14; break ; case "8002" : // 8002 Electronic Serial Number (ESN) for Cellular Phone, Alphanumeric(4 + 1 to 20) p.DataType = "Alphanumeric" ; p.raw = GetVariableLengthField(Value, p.ID.Length, 1, 20, 0); break ; case "8003" : // 8003 UPC/EAN Number and Serial Number of Returnable Asset, Alphanumeric(4 + 15 to 30) p.DataType = "Alphanumeric" ; p.raw = GetVariableLengthField(Value, p.ID.Length, 15, 30, 0); break ; case "8004" : // 8004 UPC/EAN Serial Identification, Alphanumeric(4 + 1 to 30) p.DataType = "Alphanumeric" ; p.raw = GetVariableLengthField(Value, p.ID.Length, 1, 30, 0); break ; case "8005" : // 8005 Price per Unit of Measure, Numeric (4 + 6) p.DataType = "Numeric" ; p.DataLength = 6; break ; case "8006" : // 8006 Identification of the component of a trade item, Numeric(4 + 18) p.DataType = "Numeric" ; p.DataLength = 18; break ; case "8007" : // 8007 International Bank Account Number, Alphanumeric(4 + 1 to 30) p.DataType = "Alphanumeric" ; p.raw = GetVariableLengthField(Value, p.ID.Length, 1, 30, 0); break ; case "8008" : // 8008 Date and Time of Production, Numeric(4 + 8 to 12) p.DataType = "Numeric" ; p.raw = GetVariableLengthField(Value, p.ID.Length, 8, 12, 0); break ; case "8018" : // 8018 EAN.UCC Global Service Relation Number, Numeric(4 + 18) p.DataType = "Numeric" ; p.DataLength = 18; break ; case "8020" : // 8020 Payment Slip Reference Number, Alphanumeric(4 + 1 to 25) p.DataType = "Alphanumeric" ; p.raw = GetVariab leLengthField(Value, p.ID.Length, 1, 25, 0); break ; default : // don't know what it is so assume a variable length field p.raw = GetVariableLengthField(Value, p.ID.Length, 1, 65535, 0); break ; } break ; case "81" : // Coupon details p.ID = Value.Substring(0, 4); switch (p.ID) { case "8100" : // 8100 Coupon Extended Code: Number System and Offer, Numeric(4 + 6) p.DataType = "Numeric" ; p.DataLength = 6; break ; case "8101" : // 8101 Coupon Extended Code: Number System, Offer, End of Offer, Numeric(4 + 10) p.DataType = "Numeric" ; p.DataLength = 10; break ; case "8102" : // 8102 Coupon Extended Code: Number System preceded by 0, Numeric(4 + 2) p.DataType = "Numeric" ; p.DataLength = 2; break ; case "8110" : // 8110 Coupon Code Identification for Use in North America, Alphanumeric(4 + 1 to 30) p.DataType = "Alphanumeric" ; p.raw = GetVariableLengthField(Value, p.ID.Length, 1, 30, 0); break ; default : // don't know what it is so assume a variable length field p.raw = GetVariableLengthField(Value, p.ID.Length, 1, 65535, 0); break ; } break ; case "90" : // Mutually Agreed Between Trading Partners, Alphanumeric(2 + 1 to 30) case "91" : // Internal Company Codes, Alphanumeric(2 + 1 to 30) case "92" : // Internal Company Codes, A lphanumeric(2 + 1 to 30) case "93" : // Internal Company Codes, Alphanumeric(2 + 1 to 30) case "94" : // Internal Company Codes, Alphanumeric(2 + 1 to 30) case "95" : // Interna l Company Codes, Alphanumeric(2 + 1 to 30) case "96" : // Internal Company Codes, Alphanumeric(2 + 1 to 30) case "97" : // Internal Company Codes, Alphanumeric(2 + 1 to 30) case "98" : // Internal Company Codes, Alphanumeric(2 + 1 to 30) case "99" : // Internal Company Codes, Alphanumeric(2 + 1 to 30) p.DataType = "Alphanumeric" ; p.raw = GetVariableLengthField(Value, p.ID.Length, 1, 30, 0); break ; default : // don't know what it is so assume a variable length field with no decimals p.raw = GetVariableLengthField(Value, p.ID.Length, 1, 65535, 0); break ; } // if we couldn't figure out what the data type was, we don't recognise this string if (p.DataType == "Undefined" ) return p; // if no data length looked up it must be a variable length field if (p.DataLength == - 1) { p.DataLength = p.raw.Length - p.ID.Length; if (p.decimals != - 1) p.DataLength -- ; } // DEBATE: should this rather throw an e xception, we don't have enough data to satisfy the length requirements... if (p.DataLength + p.ID.Length > Value.Length) { // we're compensateing the length... not ideal... p.DataLength = Value.Length - p.ID.Length; if (p.decimals != - 1) p.DataLength -- ; } // get the value (remember to cater for de cimals indicator) if (p.decimals == - 1) { p.Value = Value.Substring(p.ID.Length, p.DataLength); if ( string .IsNullOrEmpty(p.raw)) p.raw = Value.Substring(0, p.ID.Length + p.DataLength); } else { // if there is no raw data, set it, length being the ID length + 1 decimal position indicator + da ta length if (p.raw.Length == 0) p.raw = Value.Substring(0, p.ID.Length + 1 + p.DataLength); // get the value without decimal point p.Value = Value.Substring(p.ID.Length + 1, p.DataLength); // check we can apply the decimal point and apply if we can if (p.Value.Length < p.decimals) throw new ArgumentOutOfR angeException ( "Decimal Point at position '" + p.decimals.ToString() + "' can't be applied to the value '" + p.Value + "'" ); else p.Value = p.Value.Substring(0, p.Value.Length - p.decimals) + "." + p.Value.Substring(p.Value.Length - p.decimals); } // TODO: add check the check digit matches up //if (p.hasCheckdigit == true) //{ // //} return p; } /// <summary> /// gets the variable length filed data /// </summary> /// <param name="Value"> stri ng representing the data bar to be decoded </param> /// <param name="IDLen"> the length of the ID part of the data bar </param> /// <param name="ValueMinLength"> min length of the data </param> /// <param name="ValueMax Length"> max length of the data </param> /// <param name="decimalIDs"> the number of characters that are part of the ID that represent the decimal point position </param> /// <returns></returns> private static string G etVariableLengthField( string Value, int IDLen, int ValueMinLength, int ValueMaxLength, int decimalIDs) { // get the end of field marker int len = Value.IndexOf(FNC1); // if not f ound, assume the rest of the string if (len == - 1) len = Value.Length; // if we have a length larger than the value max length, make the length the max length // DEBATE: should this be an exception? if (len - IDLen - decimalIDs > ValueMaxLength) len = ValueMaxLength + IDLen; // if the filed is too short, throw an error // DEBATE: should we throw an error or accept and continue? or should we Let the consuming app validate? if (len - IDLen - decimalIDs < ValueMinLength) throw new Exception ( "The Field length is to short" ); // return the raw data including the ID return Value.Substring(0, len + decimalIDs); } /// <summary> /// looks up the DataBar's description based on the pa rt ID /// </summary> /// <remarks> see http://en.wikipedia.org/wiki/GS1 - 128</remarks > /// <param name="ID"> the ID number of the data bar part </param> /// <returns> a string description based on the ID </returns> public static string IDDescription( string ID) { string desc = "Unknown" ; switch (ID) { case "Input" : desc = "Input barcode" ; break ; case "00" : desc = "Serial Shipping Container Code (SSCC)" ; break ; case "01" : desc = "Global Trade Item Number (GTIN)" ; break ; case "02" : desc = "GTIN of Contained Trade Items" ; break ; case "10" : desc = "Batch/Lot Number" ; break ; case "11" : desc = "Production Date (YYMMDD - DD may be 00)" ; break ; case "12" : desc = "Due Date (YYMMDD - DD may be 00)" ; break ; case "13" : desc = "Packaging Date (YYMMDD - DD may be 00)" ; break ; case "15" : desc = "Sell by Date (Quality Control) (YYMMDD - DD may be 00)" ; break ; case "17" : desc = "Expiration Date (YYMMDD - DD may be 00)" ; break ; case "20" : desc = "Product Variant" ; break ; case "21" : desc = "Serial Number" ; break ; case "22" : desc = "Secondary Data Fields" ; break ; case "240" : desc = "Additional Product Identificat ion" ; break ; case "241" : desc = "Customer Part Number" ; break ; case "242" : desc = "Made - to - Order Variation Number" ; break ; case "250" : desc = "Secondary Serial Number" ; break ; case "251" : desc = "Reference to Source Entity" ; break ; case "253" : desc = "Global Document Type Identifier" ; break ; case "254" : desc = "GLN Extension Component" ; break ; case "30" : desc = "Count of items" ; break ; case "310" : desc = "Product Net Weight in kg" ; break ; case "311" : desc = "Product Length/1st Dimension, in meters" ; break ; case "312" : desc = "Product Width/Diameter/2nd Dimension, in meters" ; break ; case "313" : desc = "Product Depth/Thickness/Height/3rd Dimension, in meters" ; break ; case "314" : desc = "Product Area, in square meters" ; break ; case "315" : desc = "Product Net Volume, in liters" ; break ; case "316" : desc = "Product Net Volume, in cubic meters" ; break ; case "320" : desc = "Product Net Weight, in pounds" ; break ; case "321" : desc = "Product Length/1st Dimension, in inches" ; break ; case "322" : desc = "Product Length/1st Dimension, in feet" ; break ; case "323" : desc = "Product Length/1st Dimension, in yards" ; break ; case "324" : desc = "Product Width/Diameter/2nd Dimension, in inches" ; break ; case "325" : desc = "Product Wi dth/Diameter/2nd Dimension, in feet" ; break ; case "326" : desc = "Product Width/Diameter/2nd Dimension, in yards" ; break ; case "327" : desc = "Product Depth/Thickness/Height/3rd Dimension, in inches" ; break ; case "328" : desc = "Product Depth/Thickness/Height/3rd Dimension, in feet" ; break ; case "329" : desc = "Product Depth/Thickness/3rd Dimension, in yards" ; break ; case "330" : desc = "Logistic weight (kg)" ; break ; case "331" : desc = "Container Length/1st Dimension (Meters)" ; break ; case "332" : desc = "Container Width/Diameter/2nd Dimension (Meters)" ; break ; case "333" : desc = "Container Depth/Thickness/3rd Dimension (Meters)" ; break ; case "334" : desc = "Container Area (Square Meters)" ; break ; case "335" : desc = "Container Gross Volum e (Liters)" ; break ; case "336" : desc = "Container Gross Volume (Cubic Meters)" ; break ; case "340" : desc = "Container Gross Weight (Pounds)" ; break ; case "341" : desc = "Container Length/1st Dimension, in inches" ; break ; case "342" : desc = "Container Length/1st Dimension, in feet" ; break ; case "343" : desc = "Container Length/1st Dimension in, in yards" ; break ; case "344" : desc = "Container Width/Diameter/2nd Dimension, in inches" ; break ; case "345" : desc = "Container Width/Diameter/2nd Dimension, in feet" ; break ; case "346" : desc = "Container Width/Diameter/2nd Dimension, in yards" ; break ; case "347" : desc = "Container Depth/Thickness/Height/3rd Dimension, in inches" ; break ; case "348" : desc = "Container Depth/Thickness/Height/3r d Dimension, in feet" ; break ; case "349" : desc = "Container Depth/Thickness/Height/3rd Dimension, in yards" ; break ; case "350" : desc = "Product Area (Square Inches)" ; break ; case "351" : desc = "Product Area (Square Feet)" ; break ; case "352" : desc = "Product Area (Square Yards)" ; break ; case "353" : desc = "Container Area (Square Inches)" ; break ; case "354" : desc = "Container Area (Square Feet)" ; break ; case "355" : desc = "Container Area (Square Yards)" ; break ; case "356" : desc = "Net Weight (Troy Ounces)" ; brea k ; case "357" : desc = "Net Weight/Volume (Ounces)" ; break ; case "360" : desc = "Product Volume (Quarts)" ; break ; case "361" : desc = "Product Volume (Gallons)" ; break ; case "362" : desc = "Container Gross Volume (Quarts)" ; break ; case "363" : desc = "Container Gross Volume (U.S. Gallons)" ; break ; case "364" : desc = "Product Volume (Cubic Inches)" ; break ; case "365" : desc = "Product Volume (Cubic Feet)" ; break ; case "366" : desc = "Product Volume (Cubic Yards)" ; break ; case "367" : desc = "Container Gross Volume (Cubic Inches)" ; break ; case "368" : desc = "Container Gross Volume (Cubic Feet)" ; break ; case "369" : desc = "Container Gross Volume (Cubic Yards)" ; break ; case "37" : desc = "N umber of Units Contained" ; break ; case "390" : desc = "Amount payable (local currency)" ; break ; case "391" : desc = "Amount payable (with ISO currency code as 1st 3 digits)" ; break ; case "392" : desc = "Amount payable per single item (local currency)" ; break ; case "393" : desc = "Amount payable per single item (with ISO currency code as 1st 3 digits)" ; break ; case "400" : desc = "Customer Purchase Order Number" ; break ; case "401" : desc = "Consignment Number (GINC)" ; break ; case "402" : desc = "Global Shipment Identification Number (G SIN)" ; break ; case "403" : desc = "Routing code" ; break ; case "410" : desc = "Ship To/Deliver To Location Code (Global Location Number)" ; break ; case "411" : desc = "Bill To/Invo ice Location Code (Global Location Number)" ; break ; case "412" : desc = "Purchase From Location Code (Global Location Number)" ; break ; case "413" : desc = "Ship for - Deliver for - Forward to Location Cod e (Global Location Number)" ; break ; case "414" : desc = "Identification of a physical location (Global Location Number)" ; break ; case "420" : desc = "Ship To/Deliver To Postal Code (Single Postal Authority)" ; break ; case "421" : desc = "Ship To/Deliver To Postal Code (with ISO country code as 1st 3 digits)" ; break ; case "422" : desc = "Country of Origin (ISO country code)" ; break ; case "423" : desc = "Country or countries of initial processing (with ISO country code as 1st 3 digits)" ; break ; case "424" : desc = "Country of processing (ISO country Code)" ; break ; case "425 " : desc = "Country of disassembly (ISO country Code)" ; break ; case "426" : desc = "Country of full process chain (ISO country Code)" ; break ; case "7001" : desc = "NATO Stock Number (NSN)" ; break ; case "7002" : desc = "UN/ECE Meat Carcasses and cuts classification" ; break ; case "7003" : desc = "Expiration date and time" ; break ; case "7004" : desc = "Active Potency" ; break ; case "7030" : desc = "Processor approval 1st signoff (with ISO country code as 1st 3 digits)" ; break ; case "7031" : desc = "Processor approval 2nd signoff (with ISO country code as 1st 3 digits)" ; break ; case "7032" : desc = "Processor approval 3rd signoff (with ISO country code as 1st 3 digits)" ; break ; case "7033" : desc = "Processor approval 4th signoff (with ISO country code as 1st 3 digits)" ; break ; case "7034" : desc = "Processor approval 5th signoff (with ISO country code as 1st 3 digits)" ; break ; case "7035" : desc = "Processor approval 6th signoff (with ISO country code as 1st 3 digits)" ; break ; case "7036" : desc = "Processor approval 7th signoff (with ISO country code as 1st 3 digits)" ; break ; case "7037" : desc = "Processor approval 8th signoff (with ISO country code as 1st 3 digits)" ; break ; case "7038" : desc = "Processor approval 9th signoff (with ISO country code as 1st 3 digits)" ; break ; case "7039" : desc = "Processor approval 10th signoff (with ISO country code as 1st 3 digits)" ; break ; case "8001" : desc = "Roll Products - Width/Length/Core Diameter/Direction/Splices" ; break ; case "8002" : desc = "Cellular Mobile Telephone Identifier" ; break ; case "8003 " : desc = "Global Returnable Asset Identifier" ; break ; case "8004" : desc = "Global Individual Asset Identifier" ; break ; case "8005" : desc = "Price per Unit of Measure" ; break ; case "8006" : desc = "Identification of the components of an item (n14+n2+n2)" ; break ; case "8007" : desc = "International Bank Account Number" ; break ; case "8008" : desc = "Date/time of production (n8+n..4)" ; break ; case "8018" : desc = "Global Service Relation Number" ; break ; case "8020" : desc = "Payment slip reference number" ; break ; case "8100" : desc = "Coupon Extended Code: Number System and Offer" ; break ; case "8101" : desc = "Coupon Extended Code: Number System, Offer, End of Offer (n1+n5+n4)" ; break ; case "8102" : desc = "Coupon Extended Code: Number System preceded by 0" ; break ; case "8110" : desc = "Coupon code ID (North America see http://www.accelotech.com/DataBarCouponBarcode.html or http://www.webscaninc.com/bar - code - chec k/gs1 - coupon - code/)" ; break ; case "90" : desc = "Mutually Agreed Between Trading Partners" ; break ; case "91" : desc = "Internal Company Code" ; break ; case "92" : desc = "Internal Company Code" ; break ; case "93" : desc = "Internal Company Code" ; break ; case "94" : desc = "Internal Company Code" ; break ; case "95" : desc = "Internal Company Code" ; break ; case "96" : desc = "Internal Company Code" ; break ; case "97" : desc = "Internal Company Code" ; break ; case "98" : desc = "Internal Company Code" ; break ; case "99" : desc = "Internal Company Code" ; break ; default : desc = "Unknown ID " + ID; break ; } return desc; } } }